/*-----------------------------------------------------------------------------
	6502 Macroassembler and Simulator
		additions
Copyright (C) 2023 Mark Spankus

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-----------------------------------------------------------------------------*/

#ifndef _SIM_OSI_H
#define _SIM_OSI_H

#define RectWidth(r) (r.right - r.left)
#define RectHeight(r) (r.bottom - r.top)

typedef struct tag_FONTSIZE
{
	int lfHeight;
	int cellWidth;
	int cellHeight;

} FONTSIZE, *lpFONTSIZE;
#define MAX_FONT_SIZES 50

BOOL MakeRectVisible(RECT& rRect);
BOOL MakeRectSized(RECT& rRect, int minx, int miny, int l, int r, int w, int h);
bool IsFontAvailable( LPCTSTR const pFontName, HDC hDC = NULL);
bool addFont( const TCHAR * szFontPath);
int load_resource(LPCTSTR name, UINT nID, BYTE *addr, DWORD length) ;
BOOL FontMappingSuccess(const HDC hdc);
BOOL CompareFonts( const TEXTMETRIC *ptm, const TCHAR *pFaceName, const LOGFONT lf);
HANDLE LoadFont(UINT uRes, const TCHAR * szFontName);

#define acia_IRQ	 '\x80'
#define acia_PE		 '\x40'
#define acia_RXO	 '\x20'
#define acia_FE		 '\x10'
#define acia_CTS	 '\x08'
#define acia_DCD     '\x04'
#define acia_TXEmpty '\x02'
#define acia_RXFull  '\x01'

enum eWordSel {SevenE2 = 0,	SevenO2,SevenE1,SevenO1,EightN2,EightN1,EightE1,EightO1	};
enum eDivideSel { DivideBy1, DivideBy16, DivideBy64, ResetACIA };
enum eXmitCtrl { RTSNOIRQ, RTSIRQ, NORTSNOIRQ, RTSBREAK };
//number of clock cycles @ 1Mhz for 1 char 8N1
enum eBaud { b110=90909,b300=33333,b600=16667,b1200=8332,b2400=4166,
			 b4800=2083,b9600=1041,b19200=521,bNoLimit=0 };
class Acia
{
public:
	Acia();
	~Acia();



	//number of clock cycles @ 1Mhz for 1 char 8N1
	enum eBaud { b110=90909,b300=33333,b600=16667,b1200=8332,b2400=4166,
				 b4800=2083,b9600=1041,b19200=521,bNoLimit=0 };

//implementation
public:

	//acia access based on memory address
	virtual void Write( unsigned int address, unsigned char writevalue);
	virtual void Read( unsigned int address, unsigned char *readvalue);
	virtual void Reset();
	virtual void clock_tick(int nClocks);
	
	//When CTS bit high, Transmit Data Register Empty is inhibited
	//CTS is an active lo (inverted) input, CTS high when not OK to send 
	virtual void SetCTS(bool bEnable) //internally we treat these as uninverted
		{  if (bEnable) m_cStatus |= acia_CTS; else m_cStatus &= ~acia_CTS; };
	//DCD bit going high causes an IRQ when Receive Interrupt Enable is set
	//DCD is an active lo (inverted) input, when input goes high it means carrier not present
	virtual void SetDCD(bool bEnable) //internally we treat these as uninverted
		{  if (bEnable) m_cStatus |= acia_DCD; else m_cStatus &= ~acia_DCD; };
	virtual void SetFE()	//set a Framming Error, cleared by Read data
		{  m_cStatus |= acia_FE;};
	virtual void SetPE()	//set a Parity Error, cleared by Read data
		{  m_cStatus |= acia_PE;};
	virtual void SetACIAIRQ() { m_bIRQSet = TRUE; };
	virtual void ClearACIAIRQ(){ m_bIRQSet = FALSE; };
	virtual bool GetRTS() { return m_eXmitCtrl == NORTSNOIRQ; }; //return TRUE when RTS disabled
	void data_write(BYTE data);
	BYTE data_read();
	void control_write(BYTE data);
	BYTE control_read();
	
	
	//support functions
	void SetFile(BOOL bInput = TRUE);			//prompt use for input or output file
	void CloseFile(BOOL bInput = TRUE);			//close file if open
	BOOL IsFileOpen(BOOL bInput = TRUE);		//determine open state
	BOOL RewindInput();
    CString GetStatus();

protected:
	long		m_nRTickCount;
	long		m_nTTickCount;		
	eDivideSel	m_eDivideSel;  
	eWordSel	m_eWordSel;	   
	eXmitCtrl	m_eXmitCtrl;   
	BOOL		m_txIRQenable; 
	BOOL		m_rxIRQenable;
	BOOL        m_bIRQConnected;
	 
	BOOL		m_bIRQSet;	   
	unsigned char m_cStatus;   //last ACIA status
	eBaud		m_eSpeed;
	unsigned char m_cOut;
	BOOL		m_bResetting;  //in reset mode

	int   m_txIRQ;			//transmit buffer empty IRQ	2 = hardware irq
	int   m_rxIRQ;			//receive buffer full IRQ	2 = hardware irq
	
	//mirror control registers
	unsigned char m_ubControl;

	HANDLE		m_hInFile;
	HANDLE		m_hOutFile;
	DWORD		m_dwReadBytes;	
	BOOL       m_bAutoSave;
	BOOL	   m_bAutoLoad;
	CString    m_szInFile;
	CString    m_szOutFile;
};

/////////////////////////////////////////////////////////////////////////////
// COSIWindow 
enum OSIEmulation { C2P = 0, C1P = 1, UK101 = 2 };

class COSIWindow : public CMiniFrameWnd, CBroadcast
{
  static CString m_strClass;
  static bool m_bRegistered;
  void RegisterWndClass();

  FONTSIZE m_FontSizes[MAX_FONT_SIZES];
  int cellWidth,cellHeight;
  int m_xoffset, m_yoffset;
  int m_nRows, m_nCols;
  int m_nKeyTick;
  unsigned int m_nVidTick;
  BOOL m_bDoubleHalf;
  BOOL m_bDoubleHeight;
  BOOL m_bC1P64x16;

  Acia m_Serial;
  
  COutputMem* m_pMem;
  
  //CInputBuffer m_InputBuffer;	// keyboard input buffer

  DECLARE_DYNCREATE(COSIWindow)
public:
  static bool m_bHidden;
  COSIWindow();           // protected constructor used by dynamic creation

  // Attributes
public:
  static CFont m_OSIFont;
  static HANDLE m_hOSITTF;
  static HANDLE m_hUK101TTF;
  static LOGFONT m_LogFont;
  static CPoint m_WndPos;		// położenie okna
  static int m_nInitW, m_nInitH;
  static COLORREF m_rgbTextColor, m_rgbBackgndColor;
  static BOOL m_bPromptRead;
  static BOOL m_bPromptWrite;
  static BOOL m_bBASIC;
  static int m_nEmulation;
  CString m_PasteBuf;
   // Operations
private:
  void CalcFontSize();			// obliczenie rozmiaru znaków
  void InitNewFont(LOGFONT LogFont);
  void LoadROMS();
public:
  enum Commands				// rozkazy dla okna terminala
  { CMD_CLS = CBroadcast::WM_USER_OFFSET+100, CMD_PUTC, CMD_PUTS, CMD_IN, CMD_POSITION };
  bool Create();
  void SetWndPos(const POINT &p);
  CPoint GetWndPos();
  void Paste();

  void CharToKeystate(unsigned char c, BOOL bShiftOnly =FALSE, BOOL bC1P = FALSE);
  void SetColors(COLORREF text, COLORREF backgnd);
  void GetColors(COLORREF &text, COLORREF &backgnd);
  void SetEmulation(int nEmu);
  int GetEmulation() { return m_nEmulation; };
  void ChangeSettings();
  unsigned char Read(int addr);
  void Write(int addr, unsigned char data);
  BOOL IsIOAddr(int addr, BOOL bWrite = FALSE );
  void Tick(int clocks);
  void ClearKeyScan(BOOL bNoCaps = FALSE);

  // Overrides
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(COSIWindow)
	public:
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	protected:
    virtual void PostNcDestroy();
	//}}AFX_VIRTUAL

  // Implementation
public:
  virtual ~COSIWindow();
protected:

  // Generated message map functions
  //{{AFX_MSG(COSIWindow)
	afx_msg void OnPaint();
	afx_msg void OnGetMinMaxInfo(MINMAXINFO* pMMI);
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnDestroy();
	afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnClose();
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
	afx_msg void OnPaste();
	//}}AFX_MSG
	afx_msg LRESULT OnStartDebug(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnExitDebug(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnMemChanged(WPARAM wParam, LPARAM lParam);	
 
public:
	afx_msg void OnSizing(UINT fwSide, LPRECT pRect);
	DECLARE_MESSAGE_MAP()
};

extern COSIWindow* g_pOSIWindow;
extern const TCHAR ENTRY_OSI[];
extern const TCHAR LAST_PATH[];
extern const TCHAR PROMPTREAD[];
extern const TCHAR PROMPTWRITE[];
extern const TCHAR BASIC[];
extern const TCHAR Emulation[];

/////////////////////////////////////////////////////////////////////////////

#endif //_SIM_OSI_H